home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Pascal / Snippets / PNL Libraries / MyDriver.p < prev    next >
Text File  |  1996-06-01  |  14KB  |  485 lines

  1. unit MyDriver;
  2.  
  3. { Code thanks to Pete Resnick }
  4.  
  5. interface
  6.  
  7.     uses
  8.         Devices;
  9.         
  10.     const
  11.         dOpened = $0020;
  12.         dRAMBased = $0040;
  13.  
  14. {$PUSH}
  15. {$ALIGN MAC68K}
  16.  
  17. { Structure of the driver resource }
  18.     type
  19.         DriverRecord = record
  20.                 drvrFlags: integer;
  21.                 drvrDelay: integer;
  22.                 drvrEMask: integer;
  23.                 drvrMenu: integer;
  24.                 drvrOpen: integer;
  25.                 drvrPrime: integer;
  26.                 drvrCtl: integer;
  27.                 drvrStatus: integer;
  28.                 drvrClose: integer;
  29.                 drvrName: Str63;
  30. { driver name and code follows }
  31.             end;
  32.         DriverPtr = ^DriverRecord;
  33.         DriverHandle = ^DriverPtr;
  34.         DCtlArray = array[0..1000] of DCtlHandle;
  35.         DCtlArrayPtr = ^DCtlArray;
  36.  
  37. {$ALIGN RESET}
  38. {$POP}
  39.  
  40. { These two routines are the ones you want to call }
  41.     function InstallRAMDriver (name: Str255; var refnum: integer; openit: boolean): OSErr;
  42.     function RemoveRAMDriver (refnum: integer): OSErr;
  43.  
  44.     function DriverIsOpen (name: Str255): boolean;
  45.  
  46. { These are used internally but might be useful in unusual circumstances }
  47.     function GetDriverRefNum (name: Str255): integer;
  48.     function SizeUTable (entries: integer): OSErr;
  49.     function DriverAvail (var unitNum: integer): OSErr;
  50.     function Get1XResource (var rsrcHndl: Handle; rsrcType: ResType; rsrcID: integer; rsrcInd: integer; rsrcName: StringPtr): OSErr;
  51.     function Get1SysXRsrc (var rsrcHndl: Handle; rsrcType: ResType; rsrcID: integer; rsrcInd: integer; rsrcName: StringPtr): OSErr;
  52.     function PtrInZone (theZone: THz; thePtr: univ Ptr): boolean;
  53.     function HandleInZone (theZone: THz; theHandle: univ Handle): boolean;
  54.  
  55. { Undefined, but documented routines }
  56.     function DriverInstall (drvrHandle: Handle; refnum: integer): OSErr;
  57.     inline
  58.         $301F, $205F, $2050, $A03D, $3E80;
  59.     function DriverRemove (refnum: integer): OSErr;
  60.     inline
  61.         $301F, $A03E, $3E80;
  62.  
  63. { Interupt enable/disable }
  64.     function DisableInterrupts: integer;
  65.     inline
  66.         $4007, $46FC, $2600;
  67.     procedure ResetStatusRegister (oldSR: integer);
  68.     inline
  69.         $46DF;
  70.  
  71. { Access low memory globals }
  72.     function LMUTableBase: DCtlArrayPtr;
  73.     inline
  74.         $2EB8, $011C;
  75.  
  76.     procedure LMSetUTableBase (addr: univ DCtlArrayPtr);
  77.     inline
  78.         $21DF, $011C;
  79.  
  80.     function LMUnitEntryCount: integer;
  81.     inline
  82.         $3EB8, $1D2;
  83.  
  84.     procedure LMSetUnitEntryCount (n: integer);
  85.     inline
  86.         $31DF, $01D2;
  87.  
  88. implementation
  89.  
  90.     uses
  91.         Resources,TextUtils;
  92.         
  93. { *    The following code is to install and remove RAM drivers in the system}
  94. { *    heap. Written by Pete Resnick with the help of J. Geagan, Joe Holt,}
  95. { *    Tom Johnson, Michael A. Libes, Charles Martin, John Norstad, Phil}
  96. { *    Shapiro, Eric Braun, David Brown and Matthias Urlichs. Feel free to}
  97. { *    use this in your code, though I do ask that you give credit. Please}
  98. { *    report any bugs to Pete Resnick - resnick@cogsci.uiuc.edu. Please read}
  99. { *    the README file and check defines in drvrincludes.h before you use}
  100. { *    this code!!}
  101. { *}
  102. { *    Change Log}
  103. { *    ----------}
  104. { *    Date:        Change:                                                Who:}
  105. { *    -----        -------                                                ----}
  106. { *    6/2/92        Changed ThinkCleanup so that it compiles and works    pr}
  107. { *    6/22/92        Corrected declaration of DisableInterrupts            eb}
  108. { *    7/1/92        Corrected declaration of DrvrInstall and DrvrRemove    eb/pr}
  109. { *    10/15/92    Changed Get1SysRsrc to Get1SysXRsrc                    pr}
  110. { *    10/18/92    Got rid of thinkReOpen; just return 1 from close    pr}
  111. { *                Fixed up PtrInZone to make it a little quicker        pr}
  112. { *    11/6/92        Got rid of auto initialize for newCode and oldCode    pr}
  113. { *                Changed PBxxx calls to PBxxxSync                    pr}
  114. { *    11/8/92        A little cleanup; moved a few things                pr}
  115. { *    12/17/92    Added HNoPurge to Get1SysXRsrc                        db/pr}
  116. { *    1/24/93        Fixed double deletion of DATA Handle and dispose    db/pr}
  117. { *                of code Handle -- major changes to all ThinkXXX}
  118. { *                routines and THINKProc.c}
  119. { *    2/5/93        Made DriverAvail a little more efficent                pr}
  120. { *    2/6/93        Re-wrote all of the Think routines and THINKProc.c    pr}
  121. { *                so that the THINK proc is a pointer instead of a}
  122. { *                Handle (needed for locked drivers).}
  123. { *    2/23/93        Passed drvrInstFlags to RemoveRAMDriver    from        pr}
  124. { *                InstallRAMDriver error}
  125. { *    10/21/93    Check for nil handles in RemoveRAMDriver            pr}
  126. { *                Zero out close block in RemoveRAMDriver}
  127. { *                Prettified GetDriverRefNum}
  128. { *                Moved DisableInterrupts, ResetInterrupts,}
  129. { *                DrvrInstall, and DrvrRemove from driver.h to}
  130. { *                drvrincludes.h}
  131. { *                    }
  132. { *    19940212    Convert to Pascal                PNL}
  133.  
  134.  
  135. { *    InstallRAMDriver will install the named driver into the system heap}
  136. { *    return the driver reference number in refNum. }
  137.  
  138.     function InstallRAMDriver (name: Str255; var refnum: integer; openit: boolean): OSErr;
  139.         var
  140.             err, junk: OSErr;
  141.             drvrHandle: Handle;
  142.             rsrcType: ResType;
  143.             rsrcID, unitNum: integer;
  144.             hndlState: SignedByte;
  145.             ctlEntryPtr: DCtlPtr;
  146.             drvrPtr: DriverPtr;
  147.             pb: ParamBlockRec;
  148.     begin
  149.  
  150.         err := noErr;
  151.  
  152.         if GetDriverRefNum(name) <> 0 then
  153.             err := badUnitErr;
  154.  
  155.         if err = noErr then
  156.             err := DriverAvail(unitNum);
  157.  
  158.         if err = noErr then
  159.             err := Get1SysXRsrc(drvrHandle, 'DRVR', 0, 0, @name);
  160. { Why not just rely on the resource being set to system and non-purgeable and just use Get1NamedResource??? }
  161.  
  162.         if err = noErr then begin
  163.             GetResInfo(drvrHandle, rsrcID, rsrcType, name);
  164.             err := ResError;
  165.  
  166.             if err = noErr then begin
  167.                 DetachResource(drvrHandle);
  168.                 err := ResError;
  169.             end;
  170.  
  171.             if err <> noErr then
  172.                 ReleaseResource(drvrHandle);
  173.         end;
  174.  
  175.         if err = noErr then begin
  176.  
  177.     { Install DRVR with the refNum.  }
  178.             refnum := -(unitNum + 1);
  179.             hndlState := HGetState(drvrHandle);
  180.             HLock(drvrHandle);
  181.             err := DriverInstall(drvrHandle, refnum);
  182.             HSetState(drvrHandle, hndlState);
  183.  
  184.     { Cleanup on errors }
  185.             if err <> noErr then
  186.                 DisposeHandle(drvrHandle);
  187.         end;
  188.  
  189.         if err = noErr then begin
  190.     { Move the important information to the driver entry }
  191.             ctlEntryPtr := GetDCtlEntry(refnum)^;
  192.             drvrPtr := DriverHandle(drvrHandle)^;
  193.             ctlEntryPtr^.dCtlDriver := Ptr(drvrHandle);
  194.             ctlEntryPtr^.dCtlFlags := BOR(drvrPtr^.drvrFlags, dRAMBased);
  195.             ctlEntryPtr^.dCtlDelay := drvrPtr^.drvrDelay;
  196.             ctlEntryPtr^.dCtlEMask := drvrPtr^.drvrEMask;
  197.             ctlEntryPtr^.dCtlMenu := drvrPtr^.drvrMenu;
  198.  
  199.     { Open the driver }
  200.             if openit then begin
  201.                 pb.ioCompletion := nil;
  202.                 pb.ioNamePtr := @name;
  203.                 pb.ioPermssn := fsCurPerm;
  204.                 err := PBOpenSync(@pb);
  205.             end;
  206.  
  207.     { If an error occurred during the open, remove the DRVR }
  208.             if err <> noErr then
  209.                 junk := RemoveRAMDriver(refnum);
  210.         end;
  211.  
  212.         InstallRAMDriver := err;
  213.     end;
  214.  
  215.  
  216. { *    RemoveRAMDriver removes the driver installed in the system heap by}
  217. { *    InstallRAMDriver.}
  218.  
  219.     function RemoveRAMDriver (refnum: integer): OSErr;
  220.         var
  221.             err: OSErr;
  222.             drvrHandle: Handle;
  223.             ctlEntryHndl: DCtlHandle;
  224.             pb: ParamBlockRec;
  225.     begin
  226.         err := noErr;
  227.  
  228.     { Get the driver control entry }
  229.         ctlEntryHndl := GetDCtlEntry(refNum);
  230.         if ctlEntryHndl = nil then
  231.             err := unitEmptyErr;
  232.  
  233.     { Check for nil Handle }
  234.         if (err = noErr) & (ctlEntryHndl^ = nil) then
  235.             err := nilHandleErr;
  236.  
  237.         if err = noErr then begin
  238.     { Get the driver Handle }
  239.             drvrHandle := Handle(ctlEntryHndl^^.dCtlDriver);
  240.  
  241. { close the driver }
  242.             if BAND(ctlEntryHndl^^.dCtlFlags, dOpened) <> 0 then begin
  243.                 pb.ioResult := 0;
  244.                 pb.ioNamePtr := nil;
  245.                 pb.ioVRefNum := 0;
  246.                 pb.ioRefNum := refNum;
  247.                 pb.ioPermssn := 0;
  248.                 err := PBCloseSync(@pb);
  249.             end;
  250.  
  251.             if err = noErr then begin
  252.     { Remove the driver }
  253.                 HLock(drvrHandle);
  254.                 err := DriverRemove(refNum);
  255.             end;
  256.  
  257. { Dispose of the driver code (nil-safe) }
  258.             DisposeHandle(drvrHandle);
  259.         end;
  260.  
  261.         RemoveRAMDriver := err;
  262.     end;
  263.  
  264.  
  265. { *    GetDriverRefNum simply searches through each driver control entry}
  266. { *    for a driver with the same name as that specified in name.}
  267. { *    If found, the reference number is returned. If no driver is found}
  268. { *    by that name, 0 is returned. Reads the low-memory global UnitNtryCnt.}
  269.  
  270.     function GetDriverRefNum (name: Str255): integer;
  271.         var
  272.             unitnum: integer;
  273.             curDCtlHndl: DCtlHandle;
  274.             curDriverPtr: DriverPtr;
  275.     begin
  276.         GetDriverRefNum := 0;
  277.         for unitnum := 0 to LMUnitEntryCount - 1 do begin
  278.             curDCtlHndl := LMUTableBase^[unitnum];
  279.             if curDCtlHndl <> nil then begin
  280.                 curDriverPtr := DriverPtr(curDCtlHndl^^.dCtlDriver); { If this is a RAM driver, it's a Handle. ROM is a pointer }
  281.                 if (curDriverPtr <> nil) & (BAND(curDCtlHndl^^.dCtlFlags, dRAMBased) <> 0) then begin
  282.                     curDriverPtr := DriverPtr(Handle(curDriverPtr)^);
  283.                 end;
  284.                 if (curDriverPtr <> nil) & EqualString(name, curDriverPtr^.drvrName, false, true) then begin
  285.                     GetDriverRefNum := -(unitNum + 1);
  286.                     leave;
  287.                 end;
  288.             end;
  289.         end;
  290.     end;
  291.  
  292.  
  293. { *    SizeUTable sets the size of the driver unit table.}
  294. { *    Interrupts must be disabled during this operation. Changes the}
  295. { *    low-memory globals UTableBase and UnitNtryCnt.}
  296.  
  297.     function SizeUTable (entries: integer): OSErr;
  298.         var
  299.             newUTableBase, oldUTableBase: Ptr;
  300.             oldSR: integer;
  301.             err: OSErr;
  302.     begin
  303.     { Make new Unit Table }
  304.         newUTableBase := NewPtrSysClear(longint(entries) * SizeOf(DCtlHandle));
  305.         err := MemError;
  306.  
  307.         if err = noErr then begin
  308.     { Any Device Manager action now would be bad! }
  309.             oldSR := DisableInterrupts;
  310.  
  311.     { Move the old Unit Table to the new Unit Table }
  312.             BlockMove(Ptr(LMUTableBase), newUTableBase, longint(LMUnitEntryCount) * SizeOf(DCtlHandle));
  313.             oldUTableBase := Ptr(LMUTableBase); { Dispose after re-enabling interupts }
  314.             LMSetUTableBase(newUTableBase);
  315.             LMSetUnitEntryCount(entries);
  316.  
  317.     { Renable interrupts }
  318.             ResetStatusRegister(oldSR);
  319.  
  320.             DisposePtr(oldUTableBase);
  321.         end;
  322.         SizeUTable := err;
  323.     end;
  324.  
  325.  
  326. { *    DriverAvail finds the first available slot in the unit table to}
  327. { *    install the new device driver. It will call SizeUTable if there is}
  328. { *    not enough room in the current unit table. It will return the first}
  329. { *    available slot between LOW_UNIT and UP_UNIT. Reads the low-memory}
  330. { *    global UTableBase and may change as well as read the low-memory global}
  331. { *    UnitNtryCnt.}
  332.  
  333.     const
  334.         LOW_UNIT = 48;        { First Unit Table Entry to use        }
  335.         NEW_UNIT = 64;    { Size of a "normal" Unit Table        }
  336.         MAX_UNIT = 128;    { Maximum size of a Unit Table            }
  337.         UP_UNIT = 4;        { Size to bounce up Unit Table            }
  338.  
  339.     function DriverAvail (var unitNum: integer): OSErr;
  340.         var
  341.             unitIndex: integer;
  342.             UTableSize: integer;
  343.             newsize: integer;
  344.             err: OSErr;
  345.     begin
  346.         err := noErr;
  347.         unitNum := 0;
  348.  
  349.         { Look for an empty slot in what's already there }
  350.         for unitIndex := LOW_UNIT to LMUnitEntryCount - 1 do begin
  351.             if LMUTableBase^[unitIndex] = nil then begin
  352.                 unitNum := unitIndex;
  353.                 leave;
  354.             end;
  355.         end;
  356.  
  357.         if unitnum = 0 then begin
  358.             UTableSize := GetPtrSize(Ptr(LMUTableBase)) div SizeOf(DCtlHandle); { the real size of the table }
  359.  
  360.             if (LOW_UNIT < UTableSize) & (LMUnitEntryCount < UTableSize) then begin
  361.                 { We can fit the new entry in the current table }
  362.                 if LMUnitEntryCount < LOW_UNIT then begin { Expand to LOW_UNIT first }
  363.                     LMSetUnitEntryCount(LOW_UNIT);
  364.                 end;
  365.                 unitNum := LMUnitEntryCount;
  366.                 LMSetUnitEntryCount(LMUnitEntryCount + 1);
  367.                 err := noErr;
  368.             end
  369.             else if UTableSize < MAX_UNIT then begin
  370.                 { we *can* increase the table size }
  371.                 newsize := UTableSize + UP_UNIT;
  372.                 if newsize < NEW_UNIT then begin
  373.                     newsize := NEW_UNIT;
  374.                 end
  375.                 else if newsize > MAX_UNIT then begin
  376.                     newsize := MAX_UNIT;
  377.                 end;
  378.                 unitNum := LMUnitEntryCount;
  379.                 err := SizeUTable(newsize);
  380.                 if err <> noErr then begin
  381.                     unitNum := 0;
  382.                 end;
  383.             end
  384.             else begin
  385.                 err := unitTblFullErr;
  386.             end;
  387.         end;
  388.  
  389.         DriverAvail := err;
  390.     end;
  391.  
  392.  
  393. { *    Get1XResource gets a Handle to a resource. The resource}
  394. { *    will be retrieved according to resource type and either resource name,}
  395. { *    or resource index, or resource ID, in that order, whichever is}
  396. { *    non-zero.}
  397.  
  398.     function Get1XResource (var rsrcHndl: Handle; rsrcType: ResType; rsrcID: integer; rsrcInd: integer; rsrcName: StringPtr): OSErr;
  399.         var
  400.             err: OSErr;
  401.     begin
  402.         if rsrcName <> nil then begin
  403.             rsrcHndl := Get1NamedResource(rsrcType, rsrcName^);
  404.         end
  405.         else if rsrcInd <> 0 then begin
  406.             rsrcHndl := Get1IndResource(rsrcType, rsrcInd);
  407.         end
  408.         else begin
  409.             rsrcHndl := Get1Resource(rsrcType, rsrcID);
  410.         end;
  411.         err := ResError;
  412.         if (err = noErr) & (rsrcHndl = nil) then
  413.             err := resNotFound;
  414.         Get1XResource := err;
  415.     end;
  416.  
  417.  
  418. { *    Get1SysXRsrc gets a Handle to the requested resource making sure that}
  419. { *    both the resource itself and the master pointer are in the system heap}
  420. { *    and non-purgeable. }
  421.  
  422.     function Get1SysXRsrc (var rsrcHndl: Handle; rsrcType: ResType; rsrcID: integer; rsrcInd: integer; rsrcName: StringPtr): OSErr;
  423.         var
  424.             savedZone, tempSysZone: THz;
  425.             err, ptrCode: OSErr;
  426.     begin
  427.     { Make sure everything loads in the system heap }
  428.         savedZone := GetZone;
  429.         tempSysZone := SystemZone;
  430.         SetZone(tempSysZone);
  431.         SetResLoad(true);
  432.  
  433.         err := Get1XResource(rsrcHndl, rsrcType, rsrcID, rsrcInd, rsrcName);
  434.         if (err = noErr) & not HandleInZone(tempSysZone, rsrcHndl) then begin
  435.             ReleaseResource(rsrcHndl);
  436.             err := Get1XResource(rsrcHndl, rsrcType, rsrcID, rsrcInd, rsrcName);
  437.         end;
  438.         if (err = noErr) & not HandleInZone(tempSysZone, rsrcHndl) then begin
  439.             ReleaseResource(rsrcHndl);
  440.             err := memAZErr;
  441.         end;
  442.         if err = noErr then begin
  443.             HNoPurge(rsrcHndl);
  444.         end;
  445.  
  446.     { Restore the zone to what it was }
  447.         SetZone(savedZone);
  448.         Get1SysXRsrc := err;
  449.     end;
  450.  
  451.  
  452. { *    PtrInZone just checks to see whether the specified pointer is within}
  453. { *    the specified zone.}
  454.  
  455.     function PtrInZone (theZone: THz; thePtr: univ Ptr): boolean;
  456.         var
  457.             stripMask, testPtr, dataStart, dataLim: longint;
  458.     begin
  459.         testPtr := longint(StripAddress(thePtr));
  460.         dataStart := longint(StripAddress(@theZone^.heapData));
  461.         dataLim := longint(StripAddress(theZone^.bkLim));
  462.         PtrInZone := (dataStart <= testPtr) & (testPtr < dataLim);
  463.     end;
  464.  
  465.  
  466. { *    HandleInZone just checks to see whether the specified pointer is within}
  467. { *    the specified zone.}
  468.  
  469.     function HandleInZone (theZone: THz; theHandle: univ Handle): boolean;
  470.     begin
  471.         HandleInZone := PtrInZone(theZone, theHandle) & PtrInZone(theZone, theHandle^);
  472.     end;
  473.  
  474.  
  475. { *    DriverIsOpen is self evident }
  476.  
  477.     function DriverIsOpen (name: Str255): boolean;
  478.         var
  479.             refnum: integer;
  480.     begin
  481.         refnum := GetDriverRefNum('.ipp');
  482.         DriverIsOpen := (refnum <> 0) & (BAND(GetDCtlEntry(refnum)^^.dCtlFlags, dOpened) <> 0);
  483.     end;
  484.  
  485. end.